<?php
/**
 * Created by PhpStorm.
 * User: yy
 * Date: 2019/5/9
 * Time: 16:02
 */

namespace app\common\service;

use app\common\model\airquality\AirQualityNc;
use think\facade\Config;
use think\Db;

class CommonService extends BaseService
{
    /**
     * 处理科学计数法
     * @param $mathVal
     * @return string
     * @author dutongtong
     */
    public function handleMathNum($mathVal, $num = 10)
    {
        if (strpos($mathVal, 'E') || strpos($mathVal, 'e')) {
            $needle = 'e';
            if (strpos($mathVal, 'E')) $needle = 'E';
            $valArr = explode($needle, $mathVal);

            $mathVal = number_format(floatval($valArr[0]) * bcpow(10, intval($valArr[1]), $num), 10, '.', '');
            return rtrim(rtrim($mathVal, '0'), '.');
        }
        return $mathVal;
    }

    /**
     * 获取任意日期之间的所有日期(这个函数不适用于年到年的计算)
     * @param        $start_time
     * @param        $end_time
     * @param string $format
     * @return array
     * @author yy by 2019/7/2
     */
    public function getDate($start_time, $end_time, $format = 'Y-m-d')
    {
        $stimestamp = strtotime($start_time);
        $etimestamp = strtotime($end_time);

        // 计算日期段内有多少天或多少小时
        if ($format == 'Y-m-d') {
            $days = ($etimestamp - $stimestamp) / 86400 + 1;
            // 保存每天日期
            $date = array();
            for ($i = 0; $i < $days; $i++) {
                $date[] = date($format, $stimestamp + (86400 * $i));
            }
        } else {
            $days = ($etimestamp - $stimestamp) / 3600;
            $date = array();
            for ($i = 0; $i < $days; $i++) {
                $date[] = date($format, $stimestamp + (3600 * $i)) . ':00:00';
            }
        }
        return $date;
    }

    /**
     * 处理之前调用和管控调用的七天和八天问题
     * @author yy by 2019/8/6
     * @param        $start_time
     * @param        $end_time
     * @param string $format
     * @return array
     */
    public function getMongoDate($start_time, $end_time, $format = 'Y-m-d')
    {
        $stimestamp = strtotime($start_time);
        $etimestamp = strtotime($end_time);

        // 计算日期段内有多少天或多少小时
        if ($format == 'Y-m-d') {
            $days = ($etimestamp - $stimestamp) / 86400;
            // 保存每天日期
            $date = array();
            for ($i = 0; $i < $days; $i++) {
                $date[] = date($format, $stimestamp + (86400 * $i));
            }
        } else {
            $days = ($etimestamp - $stimestamp) / 3600;
            $date = array();
            for ($i = 0; $i < $days; $i++) {
                $date[] = date($format, $stimestamp + (3600 * $i)) . ':00:00';
            }
        }
        return $date;
    }

    /**
     * 处理mongodb数据查询需要的时间(mongo截止日期不加00:00:00，会查不到截止日期当天的数据)
     * @param     $param
     * @param int $is_control
     * @return mixed
     * @author yy by 2019/5/31
     */
    public function getMongoTime($param, $is_control = 1)
    {
        $param['start_time'] = date('Y-m-d', strtotime($param['start_time'])) . ' 00:00:00';
        $param['end_time']   = $is_control ? date('Y-m-d', strtotime($param['end_time'])) . ' 00:00:00' : date('Y-m-d', strtotime($param['end_time'])) . ' 23:59:59';
        return $param;
    }

    /**
     * 排放量单位转换(四舍五入保留两位小数)
     * @param $data
     * @param $paramName
     * @return mixed
     * @author yy by 2019/6/10
     */
    public function getRealData($data, $paramName = '')
    {
        # 处理成t
        if (count($data) > 0) {
            foreach ($data as $ke => &$ve) {
                if ($paramName) {
                    ($ve[$paramName] === '' || $ve[$paramName] === '-') ? '' : ($ve[$paramName] = round($ve[$paramName] / Config::get('emission_denominator'), 2));
                } else {
                    ($ve === '' || $ve === '-') ? '' : ($ve = round($ve / Config::get('emission_denominator'), 2));
                }
            }
        }
        return $data;
    }

    /**
     * 获取工业行业ID集合(mongodb)
     * @return array|mixed
     * @author yy by 2019/6/10
     */
    public function getIndustryLimitId()
    {
        # 判断是否限制四大行业
        $isIndustryId = Config::get('industry_limit_arr_mongodb');
        if (!$isIndustryId) {
            $isIndustryIdData = Db::query('select id from basic_industry where type = 1 and delete_time = 0');
            $isIndustryId     = array_column($isIndustryIdData, 'id');
        }
        return $isIndustryId;
    }

    /**
     * 获取工业行业ID集合(mysql)
     * @return array|mixed
     * @author yy by 2019/6/10
     */
    public function getIndustryLimitIdmysql()
    {
        # 判断是否限制四大行业
        $isIndustryId = Config::get('industry_limit_arr');
        if (!$isIndustryId) {
            $isIndustryIdData = Db::query('select id from basic_industry where type = 1 and delete_time = 0');
            $isIndustryId     = '(' . implode(',', array_column($isIndustryIdData, 'id')) . ')';
        }
        return $isIndustryId;
    }

    /**
     * 获取非工业行业ID集合（mongodb）
     * @return array|mixed
     * @author yy by 2019/6/10
     */
    public function getNoIndustryLimitId()
    {
        $noIndustryId = Config::get('no_industry_limit_arr_mongodb');
        if (!$noIndustryId) {
            $noIndustryIdData = Db::query('select id from basic_industry where type = 2 and delete_time = 0');
            $noIndustryId     = array_column($noIndustryIdData, 'id');
        }
        return $noIndustryId;
    }

    /**
     * 获取公司ID集合
     * @return mixed
     * @author yy by 2019/6/10
     */
    public function getCompanyLimitId()
    {
        # 判断是否限制公司
        $companyIdMax = Config::get('company_max_id');
        if (!$companyIdMax) {
            $companyId    = Db::query('select max(id) as maxId from basic_company');
            $companyIdMax = $companyId[0]['maxId'];
        }
        return $companyIdMax;
    }

    /**
     * 获取实时企业id
     * @author yy by 2019/8/27
     * @return mixed
     */
    public function getRealCompanyId()
    {
        $companyId = Db::query('select id from basic_company where realtime_company = 1 order by id ASC');
        return $companyId;
    }

    /**
     * 获取公司ID集合（非测试公司和未软删除公司）
     * @param int $is_mysql 判断是mysql还是mongodb查询
     * @return array|mixed|string
     * @author yy by 2019/6/18
     */
    public function getCompanyIdArr($is_mysql = 0)
    {
        if ($is_mysql) {
            # mysql查询
            $companyIdArr = Config::get('company_id_arr_mysql');
            if (!$companyIdArr) {
                $data         = Db::query('select id from basic_company where industry_id <> 0  and delete_time = 0');
                $ids          = array_column($data, 'id');
                $companyIdArr = '(' . implode(',', $ids) . ')';

            }
        } else {
            # mongo查询
            $companyIdArr = Config::get('company_id_arr_mongodb');
            if (!$companyIdArr) {
                $data         = Db::query('select id from basic_company where industry_id <> 0  and delete_time = 0');
                $companyIdArr = array_column($data, 'id');
            }
        }
        return $companyIdArr;
    }

    /**
     * 获取时间区间污染物的浓度之和
     * @param array $arr_level_date
     * @param array $param
     * @return array|float|int
     * @author yy by 2019/6/20
     */

    public function getConcentration($param = [], $arr_level_date = [])
    {
        $param['start_time'] = date('Y-m-d', strtotime($param['start_time']));
        $param['end_time']   = date('Y-m-d', strtotime($param['end_time']));
        $pollutant_name      = $param['pollutant_name'];
        if ($param['station_id'] != 0) {
            $data = Db::query("select $pollutant_name, DATE_FORMAT(publish_time, '%Y-%m-%d') as publish_time
                from air_quality_station_aqi_forecast_hour 
                where region_id = ? and station_id = ? and $pollutant_name > 0 and publish_time like '%00:00:00%' and DATE_FORMAT(publish_time, '%Y-%m-%d') = DATE_FORMAT(predict_time, '%Y-%m-%d') and DATE_FORMAT(publish_time, '%Y-%m-%d') between ? and ? 
                ", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        } else {
            $data = Db::query("select $pollutant_name, DATE_FORMAT(publish_time, '%Y-%m-%d') as publish_time
                from air_quality_station_aqi_forecast_hour 
                where region_id = ? and station_id <> ? and $pollutant_name > 0 and publish_time like '%00:00:00%' and DATE_FORMAT(publish_time, '%Y-%m-%d') = DATE_FORMAT(predict_time, '%Y-%m-%d') and DATE_FORMAT(publish_time, '%Y-%m-%d') between ? and ?
                ", [$param['region_id'], $param['station_id'], $param['start_time'], $param['end_time']]);
        }
        $arr = [];
        if (count($arr_level_date) > 0) {
            foreach ($arr_level_date as $k => &$v) {
                foreach ($data as $k2 => $v2) {
                    in_array($v2['publish_time'], $v) ? $arr[$k][] = $v2[$pollutant_name] : $arr[$k][] = '';
                }
                $arr[$k] = array_sum($arr[$k]);
            }
            $concentration_total = $arr;
        } else {
            $concentration_total = array_sum(array_column($data, $pollutant_name));
        }
        return $concentration_total;
    }

    /**
     * 获取一年前的今天
     * @param $now_time
     * @return string
     * @author yy by 2019/6/25
     */
    public function getHistoryTime($now_time)
    {
        $history_year      = (int)date('Y', strtotime($now_time)) - 1;
        $history_month_day = date('m-d', strtotime($now_time));
        $history_time      = $history_year . '-' . $history_month_day;
        return $history_time;
    }

    /**
     * 根据排口计算公司单排口贡献度
     * @param int   $companyId
     * @param int   $type
     * @param float $contribute
     * @return int
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\db\exception\DataNotFoundException
     * @author  dutongtong   2019/7/3
     */
    public function evalCompanyContributeByDrain(int $companyId, int $type, $contribute)
    {
        //company_industry_monitor_nitre_day  实时企业 脱销表
        //company_industry_monitor_sulfur_day 实时企业 脱硫表
        //company_industry_monitor_simulation_day_avg 模拟企业表
        $dbList = [
            1 => ['company_industry_monitor_sulfur_day', 'company_industry_monitor_nitre_day']
        ];
        $dbName = $dbList[$companyId][$type] ?? 'company_industry_monitor_simulation_day_avg';

        return db::name($dbName)->where('company_id', $companyId)->count() / $contribute;
    }

    /**
     * 计算指定公司运行浓度及运行效率
     * @param int    $companyId
     * @param int    $type
     * @param string $beginDate
     * @param string $endDate
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @author  dutongtong   2019/7/3
     */
    public function evalCompanyOperatingMode(int $companyId, int $type, string $beginDate, string $endDate)
    {
        //company_industry_monitor_nitre_day  实时企业 脱销表
        //company_industry_monitor_sulfur_day 实时企业 脱硫表
        //company_industry_monitor_simulation_day_avg 模拟企业表
        $dbList    = [
            1 => ['company_industry_monitor_sulfur_day', 'company_industry_monitor_nitre_day']
        ];
        $fieldList = [
            1 => 'operation_concentration,operating_efficiency'
        ];
        $dbName    = $dbList[$companyId][$type] ?? 'company_industry_monitor_simulation_day_avg';
        $field     = $fieldList[$companyId] ?? 'operation_concentration_so2,operation_concentration_nox,operating_efficiency_so2,operating_efficiency_nox';
        $sql       = "select {$field} from {$dbName} where company_id = ? ";
        $val       = [$companyId];
        if ($companyId == 1) {
            $sql .= "and publish_time between ? and ?";
            array_push($val, $beginDate, $endDate);
        }
        $data = Db::query($sql,
            $val);
        return $data;
    }


    /**
     * 保留贡献度三位有效数
     * zhugeng 2019-07-22
     * @param $str int 原始数
     * @return mixed
     */
    public function contributionRound($str)
    {
        $contribution_val = self::handleMathNum($str * 100, 30);
        if ($contribution_val < 1) {
            $len         = strlen($contribution_val) - 2;
            $new_val     = $contribution_val * pow(10, $len);
            $first_index = substr($new_val, 0, 1);
            $value       = self::handleMathNum(round($contribution_val, stripos($contribution_val, $first_index) + 1), stripos($contribution_val, $first_index) + 1);
        } else {
            $value = round($contribution_val, 3);
        }
        return $value;
    }

    /**
     * 获取行业下企业的运行浓度
     * @author yy by 2019/8/26
     * @param array $param
     * @param int   $only_real 是否只返回实时企业
     * @return array
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getRealConcentration($param = [], $only_real = 0)
    {

        if ($param['is_sulfur']) {
            $table              = 'company_industry_monitor_sulfur_minute';
            $concentration_name = 'operation_concentration_so2';
            $emissions          = 'emissions';
            $gas                = 'export_flue_gas_volume';
        } else {
            $table              = 'company_industry_monitor_nitre_minute';
            $concentration_name = 'operation_concentration_nox';
            $emissions          = 'emission';
            $gas                = 'inlet_flue_gas_volume';
        }
        $commonService = new CommonService();
        if ($param['industry_id'] != 1 && $param['industry_id'] != 'all') {
            // 模拟企业
            $companyIdArr           = $commonService->getCompanyIdArr(1);
            $industry_limit_arr     = $param['industry_id'] == 'all' || !isset($param['industry_id']) ? $commonService->getIndustryLimitIdmysql() : '(' . $param['industry_id'] . ')';
            $simulate_concentration = Db::query("select company_id, avg($concentration_name) as concentration
                                            from company_industry_monitor_simulation_hour_avg 
                                            where company_id in $companyIdArr and industry_id in $industry_limit_arr
                                            group by company_id");
            return $simulate_concentration;
        }
        $mongodb_huanxin    = new \MongoDB\Driver\Manager(Config::get('mongodb_url'));
        $new_time           = $commonService->getMongoTime($param, 0);
        $document           = [
            'aggregate'    => $table,
            'pipeline'     => [
                [
                    '$project' => [
                        'publish_time'            => 1,
                        'company_id'              => 1,
                        'industry_id'             => 1,
                        'operation_concentration' => 1,
                        $emissions                => 1,
                        $gas                      => 1,
                    ],
                ],
                [
                    '$match' => [
//                        'industry_id'             => (int)$param['industry_id'],
                        'operation_concentration' => ['$ne' => 0],
                        'publish_time'            => [
                            '$gte' => $new_time['start_time'],
                            '$lte' => $new_time['end_time'],
                        ],
                    ]
                ],
                [
                    '$group' => [
                        '_id'             => '$company_id',
                        'emissions_total' => ['$sum' => '$' . $emissions],
                        'gas_total'       => ['$sum' => '$' . $gas]
//                        'gas_total'       => ['$sum'=>['$divide'=>['$'.$emissions, '$operation_concentration']]]
                    ]
                ],
                [
                    '$sort' => [
                        "_id" => 1,
                    ]
                ]
            ],
            'allowDiskUse' => true,
        ];
        $command            = new \MongoDB\Driver\Command($document);
        $rows               = $mongodb_huanxin->executeCommand('huanxin', $command)->toArray();
        $contribution_trend = json_decode(json_encode($rows, 320), true);
        $num                = count($contribution_trend[0]['result']);
        $real_company_id    = $commonService->getRealCompanyId();
        $real_concentration = [];
        for ($m = 0; $m < count($real_company_id); $m++) {
            $real_concentration[$m]['company_id']    = $real_company_id[$m]['id'];
            $real_concentration[$m]['concentration'] = '';
        }
        if ($num > 0) {
            for ($i = 0; $i < $num; $i++) {
                $real_concentration[$i]['company_id']    = $contribution_trend[0]['result'][$i]['_id'];
                $real_concentration[$i]['concentration'] = $contribution_trend[0]['result'][$i]['gas_total'] > 0 ? round($contribution_trend[0]['result'][$i]['emissions_total'] / $contribution_trend[0]['result'][$i]['gas_total'], 1) : '';
            }
        }
        if ($only_real) {
            return $real_concentration;
        } else {
            // 模拟企业
            $companyIdArr           = $commonService->getCompanyIdArr(1);
            $industry_limit_arr     = $param['industry_id'] == 'all' || !isset($param['industry_id']) ? $commonService->getIndustryLimitIdmysql() : '(' . $param['industry_id'] . ')';
            $simulate_concentration = Db::query("select company_id, avg($concentration_name) as concentration
                                            from company_industry_monitor_simulation_hour_avg 
                                            where company_id in $companyIdArr and industry_id in $industry_limit_arr
                                            group by company_id");
            $concentration          = array_merge($simulate_concentration, $real_concentration);
            return $concentration;
        }

    }

    /**
     * 获取行业下企业多天的运行效率
     * @param array $param
     * @param int   $only_real 是否只返回实时企业
     * @return array
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getRealEfficiency($param = [], $only_real = 0)
    {
        if ($param['is_sulfur']) {
            $table           = 'company_industry_monitor_sulfur_minute';
            $efficiency_name = 'operating_efficiency_so2';
            $emissions       = 'emissions';
        } else {
            $table           = 'company_industry_monitor_nitre_minute';
            $efficiency_name = 'operating_efficiency_nox';
            $emissions       = 'emission';
        }
        $commonService = new CommonService();
        if ($param['industry_id'] != 1 && $param['industry_id'] != 'all') {
            // 模拟企业
            $companyIdArr        = $commonService->getCompanyIdArr(1);
            $industry_limit_arr  = $param['industry_id'] == 'all' || !isset($param['industry_id']) ? $commonService->getIndustryLimitIdmysql() : '(' . $param['industry_id'] . ')';
            $simulate_efficiency = Db::query("select company_id, avg($efficiency_name) as efficiency
                                            from company_industry_monitor_simulation_hour_avg 
                                            where company_id in $companyIdArr and industry_id in $industry_limit_arr
                                            group by company_id");
            return $simulate_efficiency;
        }
        $mongodb_huanxin = new \MongoDB\Driver\Manager(Config::get('mongodb_url'));
        $new_time        = $commonService->getMongoTime($param, 0);
        $document        = [
            'aggregate'    => $table,
            'pipeline'     => [
                [
                    '$project' => [
                        'publish_time'         => 1,
                        'operating_efficiency' => 1,// 运行效率
                        $emissions             => 1, //排放量
                        'industry_id'          => 1,
                        'company_id'           => 1,
                    ],
                ],
                [
                    '$match' => [
//                        'industry_id'          => (int)$param['industry_id'],
                        'operating_efficiency' => ['$ne' => 1],
                        'publish_time'         => [
                            '$gte' => $new_time['start_time'],
                            '$lte' => $new_time['end_time'],
                        ],
                    ]
                ],
                [
                    '$group' => [
                        '_id'             => '$company_id',
                        'emissions_total' => ['$sum' => '$' . $emissions], // 运行效率计算公式的分子
                        'denominator'     => ['$sum' => ['$divide' => ['$' . $emissions, ['$subtract' => [1, '$operating_efficiency']]]]], // 实际值运行效率的分母
                    ]
                ],
                [
                    '$sort' => [
                        "_id" => 1,
                    ]
                ]
            ],
            'allowDiskUse' => true,
        ];
        $command         = new \MongoDB\Driver\Command($document);
        $rows            = $mongodb_huanxin->executeCommand('huanxin', $command)->toArray(); //这里传回的是stdClass Object
        $result          = ((array)$rows[0])['result'];
        foreach ($result as $k => &$v) {
            $v = (array)$v;
        }
        $real_company_id = $commonService->getRealCompanyId();
        $real_efficiency = [];
        for ($m = 0; $m < count($real_company_id); $m++) {
            $real_efficiency[$m]['company_id'] = $real_company_id[$m]['id'];
            $real_efficiency[$m]['efficiency'] = '';
        }
        $num = count($result);
        if ($num > 0) {
            for ($i = 0; $i < $num; $i++) {
                $real_efficiency[$i]['company_id'] = $result[$i]['_id'];
                $real_efficiency[$i]['efficiency'] = $result[$i]['denominator'] > 0 ? round(1 - $result[$i]['emissions_total'] / $result[$i]['denominator'], 4) : '';
            }
        }
        if ($only_real) {
            return $real_efficiency;
        } else {
            // 模拟企业
            $companyIdArr        = $commonService->getCompanyIdArr(1);
            $industry_limit_arr  = $param['industry_id'] == 'all' || !isset($param['industry_id']) ? $commonService->getIndustryLimitIdmysql() : '(' . $param['industry_id'] . ')';
            $simulate_efficiency = Db::query("select company_id, avg($efficiency_name) as efficiency
                                            from company_industry_monitor_simulation_hour_avg 
                                            where company_id in $companyIdArr and industry_id in $industry_limit_arr
                                            group by company_id");
            $efficiency          = array_merge($simulate_efficiency, $real_efficiency);
            return $efficiency;
        }
    }

    /**
     * 获取实时行业多天的排放量 & 获取实时企业多天的排放量
     * @author yy by 2019/8/28
     * @param array $param
     * @param int   $is_company 以企业分组还是以行业分组
     * @return array
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getRealCompanyEmission($param = [], $is_company = 0)
    {
        if (strtolower($param['company_pollutant_name']) == 'so2') {
            // $simulate_pollutant = 'emissions_so2_total';
            $table    = 'company_industry_monitor_sulfur_minute';//脱硫
            $emission = 'emissions';
        } else {
            // $simulate_pollutant = 'emissions_nox_total';
            $table    = 'company_industry_monitor_nitre_minute';//脱硝
            $emission = 'emission';
        }
        $commonService      = new CommonService();
        $new_time           = $commonService->getMongoTime($param, 0);
        $mongodb_huanxin    = new \MongoDB\Driver\Manager(Config::get('mongodb_url'));
        $group_id           = $is_company ? 'company_id' : 'industry_id';
        $document           = [
            'aggregate'    => $table,
            'pipeline'     => [
                [
                    '$project' => [
                        'publish_time' => 1,
                        'company_id'   => 1,
                        'industry_id'  => 1,
                        $emission      => 1,
                        'emission'     => 1,
                    ],
                ],
                [
                    '$match' => [
                        $emission      => ['$gte' => 0],
                        'publish_time' => [
                            '$gte' => $new_time['start_time'],
                            '$lte' => $new_time['end_time'],
                        ],
                    ]
                ],
                [
                    '$group' => [
                        '_id'             => [$group_id => '$' . $group_id],
                        'emissions_total' => ['$sum' => '$' . $emission],
//                        'gas_total'       => ['$sum' => '$' . $gas]
//                        'gas_total'       => ['$sum'=>['$divide'=>['$'.$emissions, '$operation_concentration']]]
                    ]
                ],
                [
                    '$sort' => [
                        "_id" => 1,
                    ]
                ]
            ],
            'allowDiskUse' => true,
        ];
        $command            = new \MongoDB\Driver\Command($document);
        $rows               = $mongodb_huanxin->executeCommand('huanxin', $command)->toArray();
        $contribution_trend = json_decode(json_encode($rows, 320), true);
        $arr                = [];
        foreach ($contribution_trend[0]['result'] as $k => $v) {
            $arr[] = [
//                'industry_id' => $v['_id']['industry_id'],
                $group_id   => $v['_id'][$group_id],
                'emissions' => $v['emissions_total'],
            ];
        }
        return $arr;
    }


}